﻿using Abp.AspNetCore.Mvc.Authorization;
using Abp.AspNetCore.SignalR.Hubs;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using NetCore.Controllers;
using NetCore.Filters;
using System;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace NetCore.Web.Controllers
{
    [AbpMvcAuthorize]
    public class HomeController : NetCoreControllerBase
    {
        //private IHubContext<NotifyHub> _context;
        private IHubContext<AbpCommonHub> _hubContext;
        //private INeedService _needService;
        public HomeController(
            //INeedService needService,
            //IHubContext<NotifyHub> context,
            IHubContext<AbpCommonHub> hubContext)
        {
            //_context = context;
            _hubContext = hubContext;
        }
        //[Route("Test/Index")]//只认这个路由(特性路由)
        //使用TypeFilter 可以让CustomAuthorityActionFilterAttribute中的日志依赖注入 也不用全局注册
        //[TypeFilter(typeof(CustomAuthorityActionFilterAttribute),Order = -999)]
        [TypeFilter(typeof(CustomResourceFilterAttribute), Order = -998)]
        [AllowAnonymous]
        public ActionResult Index()
        {
            #region Asp.net 6/5大对象
            //HttpContext:http请求的上下文，任何一个环节其实都是需要httpcontext，需要的参数信息，处理的中间结果，最终的结果，都是放在httpcontext，是一个贯穿始终的对象
            //所谓的6大对象，其实就是httpcontext的六大属性
            //base.HttpContext.Request:url参数form参数 url地址 urlreferer content-encoding，就是http请求提供的各种信息，后台里面可以拿到的
            //base.HttpContext.Request.Headers["user-Agent"];包括自定义--BasicAuth; Mvc5请求信息解读是 asp.net_iisapi按照http协议解析出来的。netcore是由kestrel??单独接口解析...

            //base.HttpContext.Response：响应，
            //Application:  mvc5 里面 应用程序内的多个会话和请求之间共享信息  用来做全局，多个用户共享，统计网站请求数等  netcore里面没有这个了
            //Server :mvc5 也就是个帮助类库
            //Session:base.HttpContext.Session 用户登录验证，登录时写入，验证时获取，验证码，跳转当前页，一个用户一个session，字典式
            //Cookie:Mvc5 用户登录验证，登录时写入，验证时获取 ValidateAntiForgeryToen 保存用户数据(记住账号,访问历史);一个用户一个cokie，字典氏

            //Http协议


            #endregion

            #region 使用redis Api no pass

            //using (RedisHashService service = new RedisHashService())
            //{
            //    string countTypeField = eventData.NotifyType == NotifyType.系统消息
            //        ? "SystemNotifyCount"
            //        : "ApplicationNotifyCount";
            //    var isExist = service.HashExists($"{DatumConsts.UserUnReadNotify}_{key}", countTypeField);
            //    if (isExist)
            //    {
            //        service.HashIncrement($"{DatumConsts.UserUnReadNotify}_{key}", countTypeField, eventData.NotifyCount);
            //    }
            //    else
            //    {
            //        var notifies = await NotifyRepository.GetAll().Where(m => m.ToUserId == AbpSession.UserId && !m.IsRead).ToListAsync();
            //        service.HashSet($"{DatumConsts.UserUnReadNotify}_{key}", countTypeField, notifies.Count(m => m.NotifyType == eventData.NotifyType));
            //    }
            //}

            #endregion

            #region SignalR

            //触发客户端监听的"Receive"事件 发送obj对象给客户端
            //await _context.Clients.All.SendCoreAsync("Receive", new object[] { obj});
            //_context.Clients.All.SendCoreAsync("Receive", new object[] { });

            //await _hubContext.Clients.All.SendCoreAsync("Receive", new object[] { obj});
            //_hubContext.Clients.All.SendCoreAsync("Receive", new object[] { });

            #endregion

            //MVC5:
            //View--ViewResult--ActionResult 
            //1、找cshtml---交给viewEngineCollection来findview
            //2、生成html输入response,找的是一个cshtml,这里变成了一个IView，就可以生成html输出了
            //如果你也需要写个框架，前后端混合在一起，才能生成动态数据，你会怎么设计呢？
            //设计--模板--模板特殊标签--根据标签替换 {{Name}}--根据标签替换--不同的数据会产生不同的页面(发布系统) 
            //但是，这种不够灵活，或者写不出来（多层对象属性，viewbg.tile或者for循环，需要反射，因为模板不可能太智能)
            //还有个思路：就是把整个cshtml生成一个类，把html当成字符串拼装起来，那就很灵活了，
            //既然是后台代码为什么修改后不用编译就能直接看到效果呢？因为再次被编译（md5文件监控，有变化就重新编译）
            //通过反射找到类型--找dll--找到C:\Users\parakeet\AppData\Local\Temp\VS\... 临时文件夹--4个dll 动态编译的dll
            //每个cshtml会生成一个类（WebViewPage）--execute方法，一个文件夹会生成一个dll
            //通过扩展 可以达到一套后台多套前端...

            //netcore 里面 前端页面的父类是 RazorPageBase
            return View();
        }

        //[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
        //public IActionResult Error()
        //{
        //    return View(new ErrorDto { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
        //}


        public async Task MyWebSocket(string name)
        {
            if (HttpContext.WebSockets.IsWebSocketRequest)
            {
                await ProcessChart(await HttpContext.WebSockets.AcceptWebSocketAsync());
            }
            else
            {
                await HttpContext.Response.WriteAsync("我不处理");
            }
        }

        public async Task ProcessChart(WebSocket socket)
        {
            //var buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes("服务器向客户端发送了一条消息"));
            var cancleToken = new CancellationToken();
            //await socket.SendAsync(buffer,WebSocketMessageType.Text,true,cancleToken);

            while (socket.State == WebSocketState.Open)
            {
                var buffer = new ArraySegment<byte>(new byte[4096]);
                var result = await socket.ReceiveAsync(buffer, cancleToken);
                var clientMessage = Encoding.UTF8.GetString(buffer.Array, 0, buffer.Count);
                Console.WriteLine($"{clientMessage}");
            }

        }

    }
}
